/**
 ******************************************************************************
 * @file	fpga-20c.h
 * @brief	fpga-20c 存储器通信

采用原始 fpga-20c SPI通信协议

bug
	fpga 自身返回序列有缺陷，普通的控制命令容易错乱，主控端需要多次重复读取，
	返回OTDR数据是否有错误无法得知，
 *
 @section Platform
	-#
 @section Library
	-#
 *
 * @section Depend
 *	-# spi_mxs.ko
 *	-# spidev.ko

- 2016-10-21,MenglongWu,MenglongWoo@aliyun.com
*/

#ifndef _FPGA_20C_H_
#define _FPGA_20C_H_

/** @defgroup fpga_20c
  * @{
  */
struct fpga_dev {
	int fd;					///<
	char pid;				///<
	char *desc;				///<
};

struct fpga_test_param {
	unsigned short laser;	///< 激光器波长，支持1310、1550、1625
	unsigned short pulse;	/*!< 脉冲宽度 @ref 各量程脉冲列表 同一脉宽值在同量程下取值方式不同
				300m 量程可用脉宽 @ref 脉冲列表300m
				20Km 量程可用脉宽 @ref 脉冲列表20Km
				100Km 量程可用脉宽 @ref 脉冲列表 100Km
				180Km 量程可用脉宽 @ref 脉冲列表180Km */
	unsigned short freq;	///< 频率选择 @ref 采样时钟选择
	unsigned short adopt_pt;///< 采样点数
	unsigned short add_cnt;	///< 累加次数
	char amp;		///< 放大倍数 跨阻 @ref 运放控制
	char apd_vol;		///< APD电压  可选电压 @ref APD电压范围
	char power;		///< 激光器功率 可选档位 @ref 光功率控制
	char isrun;		///< 是否启动
};

/** @defgroup 各量程脉冲列表
* @{
* @brief	每个量程下脉冲宽度与 @ref 采样时钟选择 有直接关系
* 
* 例如TP_PULSE_100KM_5120_NS与TP_PULSE_180KM_10240_NS对应的值均是128，但生成的
* 脉冲宽度不同，本质在于两100Km量程下采样始终25MHz，180Km量程12MHz

<table>
<tr><th>量程(km) <th>采样频率(MHz) 	<th>采样时间(ms)	<th>光往返时间(ms)	<th>脉冲周期(ms)	<th>1s内单个时钟对应的累加次数
<tr><td>1	<td>  800		<td>0.04		<td>0.01		<td>0.1 		<td>10000
<tr><td>5	<td>  400		<td>0.08		<td>0.05		<td>0.3125 		<td>3200
<tr><td>10	<td>  200		<td>0.16		<td>0.1			<td>0.5			<td>2000
<tr><td>30	<td>  100		<td>0.32		<td>0.3			<td>1 			<td>1000
<tr><td>60	<td>  50		<td>0.64		<td>0.6			<td>1			<td>1000
<tr><td>100	<td>  25		<td>1.28		<td>1			<td>2.666 		<td>375
<tr><td>200	<td>  12.5		<td>2.56		<td>2			<td>2.666		<td>375
</table>
*/

/** @defgroup 脉冲列表300m
* @{
*/

#define TP_PULSE_300M_5_NS	(0x5555)///<
#define TP_PULSE_300M_10_NS	(0) ///< 
#define TP_PULSE_300M_20_NS	(1) ///< 
#define TP_PULSE_300M_40_NS	(2) ///< 
/**
* @}
*/

/** @defgroup 脉冲列表1Km
* @{
*/
#define TP_PULSE_1KM_5_NS      (TP_PULSE_300M_5_NS)
#define TP_PULSE_1KM_10_NS	(0) ///< 实际20ns
#define TP_PULSE_1KM_20_NS	(1) ///< 
#define TP_PULSE_1KM_40_NS	(2) ///< 
/**
* @}
*/

/** @defgroup 脉冲列表5Km
* @{
*/
#define TP_PULSE_5KM_5_NS      (TP_PULSE_300M_5_NS)
#define TP_PULSE_5KM_10_NS	(0) ///< 实际20ns
#define TP_PULSE_5KM_20_NS	(1) ///< 
#define TP_PULSE_5KM_40_NS	(2) ///< 
#define TP_PULSE_5KM_80_NS	(4) ///< 
#define TP_PULSE_5KM_160_NS	(8) ///< 
/**
* @}
*/

/** @defgroup 脉冲列表10Km
* @{
*/
#define TP_PULSE_10KM_5_NS	(0x5555)///<
#define TP_PULSE_10KM_10_NS	(0) ///< 实际20ns
#define TP_PULSE_10KM_20_NS	(1) ///< 
#define TP_PULSE_10KM_40_NS	(2) ///< 
#define TP_PULSE_10KM_80_NS	(4) ///< 
#define TP_PULSE_10KM_160_NS	(8) ///< 
#define TP_PULSE_10KM_320_NS	(16) ///< 
/**
* @}
*/

/** @defgroup 脉冲列表30Km
* @{
*/
#define TP_PULSE_30KM_5_NS	(0x5555)///<
#define TP_PULSE_30KM_10_NS	(0) ///< 实际20ns
#define TP_PULSE_30KM_20_NS	(1) ///< 
#define TP_PULSE_30KM_40_NS	(2) ///< 
#define TP_PULSE_30KM_80_NS	(4) ///< 
#define TP_PULSE_30KM_160_NS	(8) ///< 
#define TP_PULSE_30KM_320_NS	(16) ///< 
#define TP_PULSE_30KM_640_NS	(32) ///< 对对对
/**
* @}
*/

/** @defgroup 脉冲列表60Km
* @{
*/
#define TP_PULSE_60KM_40_NS	(2) ///< 
#define TP_PULSE_60KM_80_NS	(4) ///< 
#define TP_PULSE_60KM_160_NS	(8) ///< 
#define TP_PULSE_60KM_320_NS	(16)///< 
#define TP_PULSE_60KM_640_NS	(32)///< 
#define TP_PULSE_60KM_1280_NS	(64) ///< 
/**
* @}
*/

/** @defgroup 脉冲列表100Km
* @{
*/
#define TP_PULSE_100KM_160_NS	(4) ///< 
#define TP_PULSE_100KM_320_NS	(8)///< 
#define TP_PULSE_100KM_640_NS	(16)///< 
#define TP_PULSE_100KM_1280_NS	(32) ///< 
#define TP_PULSE_100KM_2560_NS	(64) ///< 
#define TP_PULSE_100KM_5120_NS	(128) ///< 
#define TP_PULSE_100KM_10240_NS	(256) ///< 
#define TP_PULSE_100KM_20480_NS	(512) ///< 
/**
* @}
*/

/** @defgroup 脉冲列表180Km
* @{
*/
#define TP_PULSE_180KM_160_NS	(2)//(2) ///< 
#define TP_PULSE_180KM_320_NS	(4)//(4)///< 
#define TP_PULSE_180KM_640_NS	(8)//(8)///< 
#define TP_PULSE_180KM_1280_NS	(16)//(16) ///< 
#define TP_PULSE_180KM_2560_NS	(32)//(32) ///< 
#define TP_PULSE_180KM_5120_NS	(64)//(64) ///< 
#define TP_PULSE_180KM_10240_NS	(128)//(128) ///< 
#define TP_PULSE_180KM_20480_NS	(256)//(256) ///< 
/**
* @}
*/

/** end 各量程脉冲列表
* @}
*/




/** @defgroup 采样时钟选择
 * @{
 */
#define TP_FREQ_800	(800)
#define TP_FREQ_400	(400)
#define TP_FREQ_200	(200)
#define TP_FREQ_100	(100)
#define TP_FREQ_50	(50)
#define TP_FREQ_25	(25)
#define TP_FREQ_12	(12)
#define TP_FREQ_6	(6)

#define TP_FREQ_300M	TP_FREQ_800
#define TP_FREQ_1KM	TP_FREQ_800
#define TP_FREQ_5KM	TP_FREQ_400
#define TP_FREQ_10KM	TP_FREQ_200
#define TP_FREQ_30KM	TP_FREQ_100
#define TP_FREQ_60KM	TP_FREQ_50
#define TP_FREQ_100KM	TP_FREQ_25
#define TP_FREQ_180KM	TP_FREQ_12
#define TP_FREQ_200KM	TP_FREQ_12

/** end 采样时钟选择
* @}
*/
#define TP_AMP1_S1_ON	((unsigned long)(0))
#define TP_AMP1_S2_ON	((unsigned long)(0))
#define TP_AMP1_S3_ON	((unsigned long)(0))

#define TP_AMP1_S1_OFF	((unsigned long)(0x01))
#define TP_AMP1_S2_OFF	((unsigned long)(0x02))
#define TP_AMP1_S3_OFF	((unsigned long)(0x04))


/** @defgroup 运放控制
* @{
* @brief	运放4个开关 
*
* 跨阻和APD电压选择模式。S1~S3控制跨阻，S4控制二级放大倍数
* S1~S3控制的电阻分别为10K，51K，200K，低电平有效，例如S1为0互阻为10K。S4控制二
* 级放大倍数,S4为1放大倍数4倍，S4为0放大倍数1倍。
*/

/** @defgroup 运放控制开关1-3
 * @{
 */
#define TP_AMP1_ONLY_S1 (TP_AMP1_S1_ON | TP_AMP1_S2_OFF | TP_AMP1_S3_OFF) ///< 1级运放只启用开关1
#define TP_AMP1_ONLY_S2 (TP_AMP1_S2_ON | TP_AMP1_S1_OFF | TP_AMP1_S3_OFF) ///< 1级运放只启用开关2
#define TP_AMP1_ONLY_S3 (TP_AMP1_S3_ON | TP_AMP1_S1_OFF | TP_AMP1_S2_OFF) ///< 1级运放只启用开关3
/** end 运放控制开关1-3
 * @}
 */

/** @defgroup 运放控制开关4
 * @{
 */
#define TP_AMP2_S4_ON	(unsigned long)(0)	///< 打开2级运放
#define TP_AMP2_S4_OFF	(unsigned long)(0x08)	///< 关闭2级运放
/** end 运放控制开关4
 * @}
 */


#define TP_AMP1(n) (n & 0x07)	///< 运放1级放大 取值范围 @ref 运放控制开关1-3
#define TP_AMP2(n) (n & 0x08)	///< 运放2级放大 取值范围 @ref 运放控制开关4

#define TP_AMP(p1,p2) (TP_AMP1(p1) + TP_AMP2(p2)) ///< 1-2级运放设置 取值范围分别是@ref 运放控制开关1-3 @ref 运放控制开关4
/** end 运放控制
 * @}
 */











#define TP_APD_S5_ON	(unsigned char)(0x10)
#define TP_APD_S6_ON	(unsigned char)(0x20)
#define TP_APD_S5_OFF	(unsigned char)((~TP_APD_S5_ON) & 0x30)
#define TP_APD_S6_OFF	(unsigned char)((~TP_APD_S6_ON) & 0x30)
/** @defgroup APD电压范围
 * @{
 * @brief	APD 电压选择开关
 *
 * APD电压选择模式。S5，S6控制APD电压。S5~S6控制APD电压S5为1时放大倍数高，
 * S6为1时放大倍数接近为1不放大。
 */
#define TP_APD_39V	(unsigned char)(TP_APD_S5_ON | TP_APD_S6_OFF)	///< APD 39V
#define TP_APD_30V	(unsigned char)(TP_APD_S5_ON | TP_APD_S5_OFF)	///< APD 30V
/**
 * @}
 */


/** @defgroup 光功率控制
 * @{
 */
#define OTDR_LASER_PW_LV1		1 ///< 激光器功率 Level1 最小功率
#define OTDR_LASER_PW_LV2		2 ///< 激光器功率 Level2 
#define OTDR_LASER_PW_LV3		3 ///< 激光器功率 Level3 
#define OTDR_LASER_PW_LV4		4 ///< 激光器功率 Level4 最大功率
#define OTDR_LASER_PW_HIGH		OTDR_LASER_PW_LV4 ///< 激光器功率 最大功率
#define OTDR_LASER_PW_LOW		OTDR_LASER_PW_LV1 ///< 激光器功率 最大功率
/**
 * @}
 */


/** @defgroup 红光模式
  * @{
  */
#define OTDR_RL_OFF   (0)		///< 关闭红光
#define OTDR_RL_ON    (1)		///< 红光常亮 1.2ms高电平，3.7ms低电平
#define OTDR_RL_1HZ   (2)
#define OTDR_RL_10HZ  (3)
#define OTDR_RL_SLOW  OTDR_RL_1HZ	///< 红光慢闪烁 1HZ 500ms高电平，500ms低电平
#define OTDR_RL_FAST  OTDR_RL_10HZ	///< 红光快闪烁 10HZ 100ms高电平，100ms低电平
/**
 * @}
 */

/** @defgroup 低功耗模式
  * @{
  */
#define OTDR_LOW_POWER (0)	/*!< 低功耗 */
#define OTDR_OFF_POWER (1)	/*!< 关闭电源，此电源是处理器总电源，如果存在ARM与FPGA同时控制该电源，
                                     则先FPGA关断，后ARM关断*/
/**
  * @}
  */


/** @defgroup 通信光状态
  * @{
  */
#define COM_LASER (1)				///< 存在通信光
#define COM_FREE  (2)				///< 无通信光
#define IS_COM_FREE(n) (n == COM_FREE ? 0 :1)	///< OTDR 可自由发光
/**
  * @}
  */





/** @defgroup FPGA导出函数
  * @{
  */


/**
 * @brief	打开OTDR采集卡，设备挂在SPI总线上
 * @param[in]	device 设备节点
 * @param[out]	dev 设备喵师傅
 * @param[in]	ispeed 指定通信速率，传递0时采用默认500KHz
 * @retval	0  成功 dev返回有效值
 * @retval	-1 设备节点打开失败
 * @retval	-2 设备打开成功，但检测不到FPGA
 * @see fpga_close
 */
int fpga_open(char *device, struct fpga_dev **dev, unsigned long ispeed);

/**
 * @brief	关闭已打开的otdr采集卡
 * @param[in]	dev 设备描述符
 * @retval	null
 * @see fpga_open
 */
int  fpga_close(struct fpga_dev *dev);

/**
 * @brief	无用
 * @param[in]	dev 设备描述符
 * @param[in]	val 测试参数
 *		默认各量程测试参数填充 @ref 构建默认测试参数 可在默认基础上做修改
 * @retval	null
 * @remarks
 * @see fpga_read_ad
 */
unsigned int fpga_request_test(struct fpga_dev *dev, struct fpga_test_param *val);

/**
 * @brief	红光输出控制
 * @param[in]	dev 设备描述符
 * @param[in]	val 红光模式
 *		模式选择范围 @ref 红光模式
 * @retval	null
 * @remarks 该命令FPGA没有返回值，永远认为成功
 */
unsigned int fpga_red_laser(struct fpga_dev *dev, int mode);

/**
 * @brief	（作废）调节LCD背光
 * @param[in]	dev 设备描述符
 * @param[in]	val lcd 背光输出频率
 * @retval	null
 * @remarks
 * @see
 */
unsigned int fpga_lcd_bl(struct fpga_dev *dev, int val);

/**
 * @brief	（作废）获取电池状态
 * @param[in]	dev 设备描述符
 * @param[in]	status 状态
 * @retval	null
 * @remarks
 * @see
 */
unsigned int fpga_charge_status(struct fpga_dev *dev, char *status);

/**
 * @brief	fpga电源模式
 * @param[in]	dev 设备描述符
 * @param[out]	mode 选择电源模式
 *		模式选择范围 @ref 低功耗模式
 * @retval	null
 * @remarks	该命令FPGA没有返回值，永远认为成功
 * 		当选择关闭电源模式OTDR_OFF_POWER时，处理器端必须保证其数据安全保存
 */
unsigned int fpga_low_power(struct fpga_dev *dev, int mode);

/**
 * @brief	通信光检测
 * @param[in]	dev 设备描述符
 * @param[out]	status 光路通信状态
 * @retval	0 SPI正常，此时val可以是如下值 @ref 通信光状态
		可通过 IS_COM_FREE 判断
 * @retval	-1 SPI异常
 * @remarks
 * @see IS_COM_FREE
 */
unsigned int fpga_com_laser(struct fpga_dev *dev, int *status);

/**
 * @brief	读取fpga采样结果，每个采样点已32bit存储
 * @param[in]	dev 设备描述符
 * @param[out]	pt 采样点
 * @param[in]	len 采样点长度
 * @remarks	数据组成格式:以下均为16进制\n
 * 		66 23 aa bb cc 23 aa bb cc 23 aa bb cc\n
 * 		其中 66 表示数据已经准备完毕 \n
 * 		23 表示数据分割符\n
 * 		aa bb cc 是单个点累加若干次的结果，具体累加次数由 fpga_request_test 提供
 * 		转换成24byte后小端处理器需要将其转换字节序  0x00ccbbaa
 * @retval	-2 数据没有准备好
 * @retval	0 准备完毕
 * @see	fpga_request_test
 */
unsigned int fpga_read_ad(struct fpga_dev *dev, unsigned long *pt, unsigned long len);

/** @defgroup 构建默认测试参数
 * @{
 * @brief	为何存在自动配置 
 *
 * 所谓的自动配置并不是真的自动配置，而是因为采样时钟测量距离、测量脉宽之间
 * 关系密切，所以启动一个测试量程测试前先用对应的 AUTO_BUILD_xxx 构造结构体
 * struct fpga_test_param 模板，然后再根据需要做细微修改，如激光器(laser)、运放
 * (amp)、APD电压(apd)等
 * 
 * @see 各量程脉冲列表 
 * @see 采样时钟选择
 */
#define AUTO_BUILD_300M(ptr)	\
	{ \
		struct fpga_test_param *p = (struct fpga_test_param *)ptr; \
		p->laser    = 1310;\
		p->pulse    = TP_PULSE_1KM_40_NS ;\
		p->freq     = TP_FREQ_1KM ;\
		p->adopt_pt = 32000 ;\
		p->add_cnt  = 10000 ;\
		p->amp      = TP_AMP(TP_AMP1_ONLY_S1, TP_AMP2_S4_OFF) ;\
		p->apd_vol  = TP_APD_39V ;\
		p->power    = OTDR_LASER_PW_LV1 ;\
		p->isrun    = 1; \
	} ///< 默认 300M 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_1KM(ptr)	\
	{ \
		struct fpga_test_param *p = (struct fpga_test_param *)ptr; \
		p->laser    = 1310;\
		p->pulse    = TP_PULSE_5KM_160_NS ;\
		p->freq     = TP_FREQ_5KM ;\
		p->adopt_pt = 32000 ;\
		p->add_cnt  = 10000 ;\
		p->amp      = TP_AMP(TP_AMP1_ONLY_S1, TP_AMP2_S4_ON) ;\
		p->apd_vol  = TP_APD_39V ;\
		p->power    = OTDR_LASER_PW_LV2 ;\
		p->isrun    = 1; \
	}///< 默认 1KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_5KM(ptr)	\
	{ \
		struct fpga_test_param *p = (struct fpga_test_param *)ptr; \
		p->laser    = 1310;\
		p->pulse    = TP_PULSE_5KM_160_NS ;\
		p->freq     = TP_FREQ_5KM ;\
		p->adopt_pt = 32000 ;\
		p->add_cnt  = 10000 ;\
		p->amp      = TP_AMP(TP_AMP1_ONLY_S2, TP_AMP2_S4_ON) ;\
		p->apd_vol  = TP_APD_39V ;\
		p->power    = OTDR_LASER_PW_LV2;\
		p->isrun    = 1; \
	} ///< 默认 5KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_10KM(ptr)	\
	{ \
		struct fpga_test_param *p = (struct fpga_test_param *)ptr; \
		p->laser    = 1310;\
		p->pulse    = TP_PULSE_10KM_320_NS ;\
		p->freq     = TP_FREQ_10KM ;\
		p->adopt_pt = 32000 ;\
		p->add_cnt  = 10000 ;\
		p->amp      = TP_AMP(TP_AMP1_ONLY_S2, TP_AMP2_S4_ON) ;\
		p->apd_vol  = TP_APD_39V ;\
		p->power    = OTDR_LASER_PW_LV2;\
		p->isrun    = 1; \
	} ///< 默认 10KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_60KM(ptr) \
	{ \
		struct fpga_test_param *p = (struct fpga_test_param *)ptr; \
		p->laser    = 1310;\
		p->pulse    = TP_PULSE_60KM_1280_NS ;\
		p->freq     = TP_FREQ_60KM ;\
		p->adopt_pt = 32000 ;\
		p->add_cnt  = 10000 ;\
		p->amp      = TP_AMP(TP_AMP1_ONLY_S2, TP_AMP2_S4_ON) ;\
		p->apd_vol  = TP_APD_39V ;\
		p->power    = OTDR_LASER_PW_LV3;\
		p->isrun    = 1; \
	}	///< 默认 60KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_100KM(ptr)	\
	{ \
		struct fpga_test_param *p = (struct fpga_test_param *)ptr; \
		p->laser    = 1310;\
		p->pulse    = TP_PULSE_100KM_10240_NS ;\
		p->freq     = TP_FREQ_100KM ;\
		p->adopt_pt = 32000 ;\
		p->add_cnt  = 10000 ;\
		p->amp      = TP_AMP(TP_AMP1_ONLY_S3, TP_AMP2_S4_ON) ;\
		p->apd_vol  = TP_APD_39V ;\
		p->power    = OTDR_LASER_PW_LV3;\
		p->isrun    = 1; \
	} ///< 默认 100KM 配置配置参数，填充 fpga_test_param
#define AUTO_BUILD_180KM(ptr)	\
	{ \
		struct fpga_test_param *p = (struct fpga_test_param *)ptr; \
		p->laser    = 1310;\
		p->pulse    = TP_PULSE_180KM_20480_NS ;\
		p->freq     = TP_FREQ_180KM ;\
		p->adopt_pt = 32000 ;\
		p->add_cnt  = 10000 ;\
		p->amp      = TP_AMP(TP_AMP1_ONLY_S3, TP_AMP2_S4_ON) ;\
		p->apd_vol  = TP_APD_39V ;\
		p->power    = OTDR_LASER_PW_LV4;\
		p->isrun    = 1; \
	} ///< 默认 200KM 配置配置参数，填充 fpga_test_param
/** end 构建默认测试参数
* @}
*/

/** end FPGA导出函数
  * @}
  */


/** end fpga_20c
  * @}
  */
#endif

